defmodule DeeprConvert do
	@moduledoc false
	require Logger

	def lookup_convert(_fields, _key, nil) do
		nil
	end
	def lookup_convert(fields, key, value) do
		Logger.debug("key:#{key}, value:#{inspect(value)}")
		case Map.get(fields, key) do
			%{:mfa => {m, f, a}} ->
				apply(m, f, [:lookup, key, value | a])
			%{:mfa => {m, f}} ->
				apply(m, f, [:lookup, key, value])
			%{type: type} when type in [:integer, :int8] ->
				to_integer!(key, value)
			%{type: :string} ->
				to_string!(key, value)
			%{type: :date} ->
				to_date!(key, value)
			%{type: :timestamp} ->
				to_timestamp!(key, value)
			_ ->
				value
		end
	end


	# 把查询后的值转换, 在各个 field 上设置相应的mfa
	def flake_id_convert(:guard, mod, select, rows, keys) do
		fields = mod.fields()
		keys = Enum.filter(select, &(&1 in keys))
		if keys != [] do
			Enum.map(
				rows,
				fn (row) ->
					Enum.reduce(
						keys,
						row,
						fn (key, acc) ->
							case Map.get(fields, key) do
								%{:mfa => {m, f, a}} ->
									v = apply(m, f, [:guard, key, Map.get(acc, key) | a])
									Map.put(acc, key, v)
								%{:mfa => {m, f}} ->
									v = apply(m, f, [:guard, key, Map.get(acc, key)])
									Map.put(acc, key, v)
								_ ->
									acc
							end
						end
					)
				end
			)
		else
			rows
		end
	end


	# 返回变成 string
	def to_string(:guard, key, v) do
		to_string!(key, v)
	end
	# 查询变成 integer
	def to_string(:lookup, key, v) do
		to_integer!(key, v)
	end
	# v, 参数
	def to_string(:select, _, v) do
		v
	end

	def json_key2string(:guard, key, v, jk) when is_list(v) do
		Enum.map(v, &json_key2string(:guard, key, &1, jk))
	end
	def json_key2string(:guard, key, v, jk) do
		case v do
			%{^jk => jkv} ->
				jkv = to_string!(key, jkv)
				Map.put(v, jk, jkv)
			_ ->
				v
		end
	end
	def json_key2string(:lookup, key, v, jk) when is_list(v) do
		Enum.map(v, &json_key2string(:lookup, key, &1, jk))
	end
	def json_key2string(:lookup, key, v, jk) do
		case v do
			%{^jk => jkv} ->
				jkv = to_integer!(key, jkv)
				Map.put(v, jk, jkv)
			_ ->
				v
		end
	end
	def json_key2string(_, _key, v, _jk) do
		v
	end
	def json_key2string(_, _key, v) do
		v
	end

	def to_integer!(key, value) when is_integer(value) do
		value
	end
	def to_integer!(key, value) when is_binary(value) do
		case Integer.parse(value) do
			{i, _} ->
				i
			_ ->
				PrivateCandy.debug_remind(__ENV__, "#{key} #{value} invalid")
		end
	end
	def to_integer!(key, value) when is_float(value) do
		PrivateCandy.debug_remind(__ENV__, "#{key} #{value} invalid")
	end
	def to_integer!(key, str) when is_list(str) do
		Enum.map(str, &to_integer!(key, &1))
	end
	def to_integer!(_key, nil) do
		nil
	end
	def to_integer!(key, value) do
		PrivateCandy.debug_remind(__ENV__, "#{key} #{inspect(value)} invalid")
	end



	def to_string!(_key, str) when is_integer(str) do
		Integer.to_string(str)
	end
	def to_string!(_key, str) when is_float(str) do
		Float.to_string(str)
	end
	def to_string!(_key, str) when is_binary(str) do
		str
	end
	def to_string!(key, str) when is_list(str) do
		Enum.map(str, &to_string!(key, &1))
	end
	def to_string!(key, nil) do
		nil
	end
	def to_string!(key, str) do
		PrivateCandy.debug_remind(__ENV__, "#{key} #{inspect(str)} invalid")
	end

	def to_date!(key, date) when is_binary(date) do
		case Date.from_iso8601(date) do
			{:ok, date} ->
				date
			_ ->
				PrivateCandy.debug_remind(__ENV__, "#{key} #{inspect(date)} invalid")
		end
	end
	def to_date!(_key, date) when is_struct(date, Date) do
		date
	end
	def to_date!(_key, date) when is_struct(date, NaiveDateTime) do
		NaiveDateTime.to_date(date)
	end
	def to_date!(key, date) when is_list(date) do
		Enum.map(date, &to_date!(key, &1))
	end
	def to_date!(_key, nil) do
		nil
	end
	def to_date!(key, date)  do
		PrivateCandy.debug_remind(__ENV__, "#{key} #{inspect(date)} invalid")
	end

	def to_timestamp!(key, date) when is_binary(date) do
		case NaiveDateTime.from_iso8601(date) do
			{:ok, date} ->
				date
			_ ->
				PrivateCandy.debug_remind(__ENV__, "#{key} #{inspect(date)} invalid")
		end
	end
	def to_timestamp!(_key, date) when is_struct(date, NaiveDateTime) do
		date
	end
	def to_timestamp!(key, date) when is_list(date) do
		Enum.map(date, &to_timestamp!(key, &1))
	end
	def to_timestamp!(_key, nil) do
		nil
	end
	def to_timestamp!(key, date)  do
		PrivateCandy.debug_remind(__ENV__, "#{key} #{inspect(date)} invalid")
	end



end
